﻿using System.ComponentModel;
using System.Configuration;
using System.Reflection;
using AutoTest.Business.IServices.Common;
using AutoTest.Business.Options;
using AutoTest.Common.Extension;
using AutoTest.Domain;
using AutoTest.Domain.Entities;
using AutoTest.Framework.Exceptions;
using AutoTest.Framework.Ioc;
using Microsoft.Extensions.Hosting;
using NPOI.OpenXmlFormats;
using Org.BouncyCastle.Asn1.Mozilla;
using SqlSugar;

namespace AutoTest.Business.Services.Common
{
    /// <summary>
    /// 数据库服务
    /// </summary>
    public class DatabaseService(ISqlSugarClient db, IHostEnvironment hostEnvironment,IRedisCacheService redisCacheService) : IDatabaseService, IScoped
    {
        private readonly ISqlSugarClient _db = db;
        private readonly IHostEnvironment _hostEnvironment = hostEnvironment;
        private readonly IRedisCacheService _redisCacheService = redisCacheService;

        /// <summary>
        /// 初始化表和数据库
        /// </summary>
        public void CreateTables()
        {
            if (_db.DbMaintenance.CreateDatabase())
            {
                var assembly = Assembly.GetAssembly(typeof(AutoTestDomainModule));
                var entityTypes = assembly?.DefinedTypes.Where(x => typeof(AllBaseEntity).IsAssignableFrom(x) && x.Name != nameof(AllBaseEntity) && !x.Name.StartsWith(nameof(BaseEntity)));
                List<string> msgList = [];
                if (entityTypes?.Any() ?? false)
                {
                    foreach (var table in entityTypes)
                    {
                        try
                        {
                            _db.CodeFirst.InitTables(table);
                        }
                        catch (Exception ex)
                        {
                            msgList.Add(ex.Message);
                        }
                    }
                }
                if (msgList.Count > 0)
                {
                    throw new BusinessException(msgList.StrJoin(";"));
                }
            }
        }
        /// <summary>
        /// 创建表
        /// </summary>
        /// <param name="entityName"></param>
        public void CreateTable(string entityName)
        {
            var assembly = Assembly.GetAssembly(typeof(AutoTestDomainModule));
            var entityType = assembly?.DefinedTypes.FirstOrDefault(x => typeof(AllBaseEntity).IsAssignableFrom(x) && x.Name == entityName);
            if (entityType != null)
            {
                _db.CodeFirst.InitTables(entityType);
            }
        }

        /// <summary>
        /// 创建应用的配置
        /// </summary>
        /// <returns></returns>
        public async Task CreateAppSetting()
        {
            var optionTypeList = Assembly.GetExecutingAssembly().DefinedTypes.Where(t => typeof(IDbOption).IsAssignableFrom(t) && t.IsClass).ToList();
            var settingList = new List<Setting>();
            foreach (var optionType in optionTypeList)
            {
                var optionSettingList = CreateDbSetting(optionType, _hostEnvironment.EnvironmentName.ToLower());
                if (optionSettingList.IsNotEmpty())
                {
                    settingList.AddRange(optionSettingList);
                }
            }
            var settingKeys = settingList.Select(x => x.OptionKey).Distinct().ToList();
            if (settingList.IsNotEmpty())
            {
                await _db.Deleteable<Setting>().Where(x => settingKeys.Contains(x.OptionKey)).ExecuteCommandAsync();
                await _db.Insertable(settingList).ExecuteCommandIdentityIntoEntityAsync();
            }
        }
        /// <summary>
        /// 根据OptionKey创建配置
        /// </summary>
        /// <param name="optionKeyName"></param>
        /// <returns></returns>
        public async Task CreateAppSetting(string optionKeyName)
        {
            var optionTypeList = Assembly.GetExecutingAssembly().DefinedTypes.Where(t => typeof(IDbOption).IsAssignableFrom(t) && t.IsClass && t.Name.Equals(optionKeyName, StringComparison.CurrentCultureIgnoreCase)).ToList();
            var settingList = new List<Setting>();
            foreach (var optionType in optionTypeList)
            {
                var optionSettingList = CreateDbSetting(optionType, _hostEnvironment.EnvironmentName.ToLower());
                if (optionSettingList.IsNotEmpty())
                {
                    settingList.AddRange(optionSettingList);
                }
            }
            var settingKeys = settingList.Select(x => x.OptionKey).Distinct().ToList();
            if (settingList.IsNotEmpty())
            {
                await _db.Deleteable<Setting>().Where(x => settingKeys.Contains(x.OptionKey)).ExecuteCommandAsync();
                await _db.Insertable(settingList).ExecuteCommandIdentityIntoEntityAsync();
            }
        }
        /// <summary>
        /// 创建配置
        /// </summary>
        /// <param name="optionType"></param>
        /// <param name="env"></param>
        public static List<Setting> CreateDbSetting(Type optionType, string env)
        {
            var option = Activator.CreateInstance(optionType);
            var properties = optionType.GetProperties();
            var settingList = new List<Setting>();
            foreach (var property in properties)
            {
                var optionDescription = property.GetCustomAttribute<OptionDescription>();
                if (!(optionDescription?.Ignore ?? false))
                {
                    settingList.Add(new Setting()
                    {
                        CreateTime = DateTime.Now,
                        Env = env,
                        Key = property.Name,
                        OptionKey = ((IDbOption)option!)?.OptionKey ?? "",
                        Remark = optionDescription?.Description ?? "",
                        UpdateTime = DateTime.Now,
                        Value = property.GetValue(option)?.ToString() ?? ""
                    });
                }
                
            }
            return settingList;
        }

        /// <summary>
        /// 设置redis
        /// </summary>
        public async Task SetIncrement()
        {
            var maxPeriod =  _db.Queryable<Xue>().Where(x => !x.DelFlag).Max(t => t.Period);

            await _redisCacheService.SetIncrementAsync(maxPeriod);
        }
    }
}
